import json
from decimal import Decimal
from django.db import transaction
from django.utils import timezone
from django.views import View
from django_redis import get_redis_connection
from django.http import JsonResponse
from goods.models import SKU, Goods
from meiduo_mall.utils.views import LoginRequiredMixin
from orders.models import OrderInfo, OrderGoods
from users.models import Address


class OrderSettlementView(LoginRequiredMixin, View):

    def get(self, request):
        # 获取登录用户
        user = request.user

        # 查询地址信息
        try:
            addresses = Address.objects.filter(user=user, is_deleted=False)
        except Address.DoesNotExist:
            addresses = None

        address_list = []

        for address in addresses:
            address_list.append({
                'id': address.id,
                'province': address.province.name,
                'city': address.city.name,
                'district': address.district.name,
                'place': address.place,
                'receiver': address.receiver,
                'mobile': address.mobile
            })

        # 从Redis购物车中查询出被勾选的商品信息
        redis_conn = get_redis_connection('carts')

        item_dict = redis_conn.hgetall('carts_%s' % user.id)
        cart_selected = redis_conn.smembers('selected_%s' % user.id)

        cart = {}
        for sku_id in cart_selected:
            # cart = {
            # 商品id: 购买数量
            # }
            cart[int(sku_id)] = int(item_dict[sku_id])
            # print(cart)

        # 查询商品信息
        sku_list = []

        try:
            skus = SKU.objects.filter(id__in=cart.keys())
        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '数据库查询错误'})

        for sku in skus:
            sku_list.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image_url,
                'count': cart[sku.id],
                'price': sku.price
            })

        # 补充运费
        freight = Decimal('10.00')

        # 渲染界面
        context = {
            'addresses': address_list,
            'skus': sku_list,
            'freight': freight,
        }

        return JsonResponse({'code': 0, 'errmsg': 'ok', 'context': context})


class OrderCommitView(View):

    def post(self, request):
        json_dict = json.loads(request.body.decode())

        # 提取数据
        address_id = json_dict.get('address_id')
        pay_method = json_dict.get('pay_method')

        # 校验参数
        if not all([address_id, pay_method]):
            return JsonResponse({'code': 0, 'errmsg': '缺少必传参数'})

        # 判断address_id
        try:
            address = Address.objects.get(id=address_id)
        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '参数address_id错误'})

        # 判断pay_method
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return JsonResponse({'code': 400, 'errmsg': '参数pay_method错误'})

        # 获取登录用户
        user = request.user

        # 生成订单编号：年月日时分秒+用户编号
        order_id = timezone.localtime().strftime('%Y%m%d%H%M%S') + ('%09d' % user.id)

        # 开启一个事务
        with transaction.atomic():

            # 创建事务保存点
            save_id = transaction.savepoint()

            # 保存订单基本信息 OrderInfo（一）
            order = OrderInfo.objects.create(
                order_id=order_id,
                user=user,
                address=address,
                total_count=0,
                total_amount=Decimal('0'),
                freight=Decimal('10'),
                pay_method=pay_method,
                status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY']
                else OrderInfo.ORDER_STATUS_ENUM['UNSEND']
            )

            # 从 redis 读取购物车中被勾选的商品信息
            redis_conn = get_redis_connection('carts')
            item_dict = redis_conn.hgetall('carts_%s' % user.id)
            cart_selected = redis_conn.smembers('selected_%s' % user.id)
            carts = {}
            for sku_id in cart_selected:
                carts[int(sku_id)] = int(item_dict[sku_id])
            # 获取选中的商品id:
            sku_ids = carts.keys()

            for sku_id in sku_ids:
                while True:
                    sku = SKU.objects.get(id=sku_id)

                    # 读取原始库存

                    origin_stock = sku.stock
                    origin_sales = sku.sales


                    # 购物车购买数量
                    sku_count = carts[sku_id]

                    # 判断 SKU 库存
                    if sku_count > origin_stock:
                        # 出错就回滚
                        transaction.savepoint_rollback(save_id)
                        return JsonResponse({'code': 400, 'errmsg': '库存不足'})

                    # # SKU减少库存，增加销量
                    # sku.stock -= sku_count
                    # sku.sales += sku_count
                    # sku.save()

                    # 乐观锁更新库存和销量
                    new_stock = origin_stock - sku_count
                    new_sales = origin_sales + sku_count
                    result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock, sales=new_sales)

                    if result == 0:
                        continue

                    # 修改SPU销量
                    # sku.goods.sales += sku_count
                    # sku.goods.save()
                    while True:
                        origin_goods_sales = sku.goods.sales
                        origin_goods_id = sku.goods_id

                        # 乐观锁更新SPU销量
                        new_goods_sales = origin_goods_sales + sku_count
                        result = Goods.objects.filter(id=origin_goods_id, sales=origin_goods_sales).update(
                            sales=new_goods_sales
                        )

                        if result == 0:
                            continue

                        # 跳出循环
                        break

                    # 保存订单商品信息
                    OrderGoods.objects.create(
                        order=order,
                        sku=sku,
                        count=sku_count,
                        price=sku.price,
                    )

                    # 保存商品订单中总价和总数量
                    order.total_count += sku_count
                    order.total_amount += (sku_count * sku.price)

                    # 下单成功或者失败就跳出循环
                    break

                # 添加邮费和保存订单信息
                order.total_amount += order.freight
                order.save()

            # 清除保存点
            transaction.savepoint_commit(save_id)

        # 清除购物车中已结算的商品
        pl = redis_conn.pipeline()
        pl.hdel('carts_%s' % user.id, *cart_selected)
        pl.srem('selected_%s' % user.id, *cart_selected)
        pl.execute()

        return JsonResponse({'code': 0, 'errmsg': 'ok', 'order_id': order_id})

